﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Caching.Distributed;

namespace Devonline.AspNetCore;

/// <summary>
/// 区域和语言相关服务
/// </summary>
public class LanguageService(IHttpContextAccessor httpContextAccessor, IDistributedCache cache)
{
    private readonly HttpContext _httpContext = httpContextAccessor.HttpContext!;
    private readonly IDistributedCache _cache = cache;

    /// <summary>
    /// 获取来自客户端设置的语言, 取值顺序: Response.ContentLanguage -> Request.AcceptLanguage -> DEFAULT_LANGUAGE
    /// </summary>
    /// <returns></returns>
    public async Task<string> GetLanguageAsync()
    {
        var language = await _cache.GetStringAsync(GetCacheKey());
        if (language is not null)
        {
            return language;
        }

        if (_httpContext.Request.Headers.AcceptLanguage.Any())
        {
            language = _httpContext.Request.Headers.AcceptLanguage;
        }

        if (_httpContext.Response.Headers.ContentLanguage.Any())
        {
            language = _httpContext.Response.Headers.ContentLanguage;
        }

        if (!string.IsNullOrWhiteSpace(language))
        {
            return new AccessLanguage(language).Language;
        }

        return new AccessLanguage().Language;
    }

    /// <summary>
    /// 设置一个区域语言
    /// </summary>
    /// <param name="language">设置语言, 默认为简体中文</param>
    public async Task SetLanguageAsync(string language = DEFAULT_LANGUAGE)
    {
        await _cache.SetStringAsync(GetCacheKey(), language);
        _httpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(language)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });
    }

    /// <summary>
    /// 根据上下文用户名构造缓存键名称
    /// </summary>
    /// <returns></returns>
    private string GetCacheKey() => CACHE_USER + _httpContext.GetUserName() + CHAR_UNDERLINE + HTTP_HEADER_LANGUAGE;
}

/// <summary>
/// 表示 HTTP Header 的 Access-Language 值
/// </summary>
public class AccessLanguage
{
    /// <summary>
    /// 区域语言
    /// </summary>
    public string Language { get; private set; }
    /// <summary>
    /// 质量权重, 0~1, 最多三位小数
    /// </summary>
    public float QualityFactor { get; private set; }
    /// <summary>
    /// Gets the collection of access languages associated with the current entity.
    /// </summary>
    /// <remarks>
    /// This property provides access to the languages that are configured for the entity. Use this
    /// collection to retrieve or enumerate the available access languages.
    /// </remarks>
    public ICollection<AccessLanguage> AccessLanguages { get; private set; } = [];

    /// <summary>
    /// 默认的构造方法
    /// </summary>
    public AccessLanguage()
    {
        Language = DEFAULT_LANGUAGE;
        QualityFactor = UNIT_ZERO;
    }
    /// <summary>
    /// 根据 HTTP Header 的 Access-Language 值初始化区域和语言
    /// </summary>
    /// <param name="value"></param>
    public AccessLanguage(string value)
    {
        Language = DEFAULT_LANGUAGE;
        QualityFactor = UNIT_ZERO;
        if (!string.IsNullOrWhiteSpace(value) && value != "*")
        {
            var values = value.Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (values.Length > 0)
            {
                foreach (var item in values)
                {
                    AccessLanguages.Add(GetAccessLanguage(item));
                }

                var accessLanguage = AccessLanguages.OrderByDescending(x => x.QualityFactor).FirstOrDefault();
                if (accessLanguage is not null)
                {
                    Language = accessLanguage.Language;
                    QualityFactor = accessLanguage.QualityFactor;
                }
            }
        }
    }

    /// <summary>
    /// 返回 Accept-Language 表示的语言值
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return $"{Language}; q={QualityFactor}";
    }
    /// <summary>
    /// 从一组 AccessLanguage 字符串获取区域语言和权重值
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static AccessLanguage GetAccessLanguage(string value)
    {
        var accessLanguage = new AccessLanguage();
        var values = value.Split(";", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (values.Length > 0)
        {
            accessLanguage.Language = values[0];
            if (values.Length > 1)
            {
                //截取 q= 之后的值
                var q = values[1][2..];
                if (float.TryParse(q, out float qualityFactor))
                {
                    accessLanguage.QualityFactor = qualityFactor;
                }
            }
        }

        return accessLanguage;
    }
}